"""Admin router for license management (responsive Bootstrap 5 UI)."""
from datetime import datetime, timezone
from typing import List

from fastapi import APIRouter, Depends, Form, HTTPException, Request, Response, status, Body
from fastapi.responses import HTMLResponse, RedirectResponse, StreamingResponse
from fastapi.templating import Jinja2Templates
import math
from sqlalchemy import or_, select, update, func, delete
from sqlalchemy.ext.asyncio import AsyncSession

from ..database import get_async_session
from ..models import ActivationCode, License
from ..utils import verify_password_hash, get_remaining_time_str

import csv
import io
import os

router = APIRouter(prefix="/admin", tags=["admin"])

templates = Jinja2Templates(directory="app/templates")

ADMIN_USER = os.getenv("ADMIN_USER", "njs")
ADMIN_PASS = os.getenv("ADMIN_PASS", "pwd@njdstu163")
SESSION_COOKIE_NAME = "auth_session"


def is_authenticated(request: Request) -> bool:
    return request.session.get("user") == ADMIN_USER


def require_auth(request: Request):
    if not is_authenticated(request):
        raise HTTPException(status_code=status.HTTP_303_SEE_OTHER, headers={"Location": "/admin/login"})


@router.get("/login", response_class=HTMLResponse)
async def login_page(request: Request):
    return templates.TemplateResponse("login.html", {"request": request, "error": None})


@router.post("/login")
async def login(request: Request, username: str = Form(...), password: str = Form(...)):
    if username == ADMIN_USER and password == ADMIN_PASS:
        request.session["user"] = ADMIN_USER
        return RedirectResponse("/admin/dashboard", status_code=status.HTTP_303_SEE_OTHER)
    return templates.TemplateResponse("login.html", {"request": request, "error": "Invalid credentials"})


@router.get("/logout")
async def logout(request: Request):
    request.session.pop("user", None)
    return RedirectResponse("/admin/login", status_code=status.HTTP_303_SEE_OTHER)


@router.get("/dashboard", response_class=HTMLResponse)
async def dashboard(
    request: Request,
    session: AsyncSession = Depends(get_async_session),
    page: int = 1,
    per_page: int = 20,
    q: str = None,
):
    require_auth(request)

    # Base query for IDs based on search criteria
    id_query = select(ActivationCode.id)
    if q:
        search_term = f"%{q}%"
        id_query = id_query.where(
            or_(
                ActivationCode.raw_code.ilike(search_term),
                ActivationCode.comment.ilike(search_term),
            )
        )

    # Get total count for pagination
    count_stmt = select(func.count()).select_from(id_query.alias())
    total_count = (await session.execute(count_stmt)).scalar_one()
    total_pages = math.ceil(total_count / per_page) if total_count > 0 else 1

    # Get the IDs for the current page
    paged_ids_subquery = (
        id_query.order_by(ActivationCode.id.desc())
        .limit(per_page)
        .offset((page - 1) * per_page)
        .subquery()
    )

    # Final query to get all data for the paged IDs
    stmt = (
        select(ActivationCode, func.count(License.id), func.min(License.expires_at))
        .join(paged_ids_subquery, ActivationCode.id == paged_ids_subquery.c.id)
        .outerjoin(License, ActivationCode.id == License.code_id)
        .group_by(ActivationCode.id)
        .order_by(ActivationCode.id.desc())
    )

    rows = (await session.execute(stmt)).all()

    codes: List[dict] = []
    for ac, used, expires_at in rows:
        codes.append(
            {
                "id": ac.id,
                "raw_code": getattr(ac, "raw_code", "****"),
                "comment": ac.comment,
                "duration_days": ac.duration_days,
                "quota": ac.quota,
                "enabled": ac.enabled,
                "created_at": ac.created_at.strftime("%Y-%m-%d")
                if getattr(ac, "created_at", None)
                else "N/A",
                "used": used,
                "expires_at": expires_at,
            }
        )

    return templates.TemplateResponse(
        "dashboard.html",
        {
            "request": request,
            "codes": codes,
            "get_remaining_time_str": get_remaining_time_str,
            "current_page": page,
            "total_pages": total_pages,
            "search_query": q or "",
        },
    )


@router.post("/code/{code_id}/disable")
async def disable_code(code_id: int, request: Request, session: AsyncSession = Depends(get_async_session)):
    require_auth(request)
    await session.execute(update(ActivationCode).where(ActivationCode.id == code_id).values(enabled=False))
    await session.commit()
    return RedirectResponse("/admin/dashboard", status_code=status.HTTP_303_SEE_OTHER)


@router.post("/code/{code_id}/quota")
async def update_quota(code_id: int, request: Request, new_quota: int = Form(...), session: AsyncSession = Depends(get_async_session)):
    require_auth(request)
    await session.execute(update(ActivationCode).where(ActivationCode.id == code_id).values(quota=new_quota))
    await session.commit()
    return RedirectResponse("/admin/dashboard", status_code=status.HTTP_303_SEE_OTHER)


@router.post("/code/{code_id}/delete")
async def delete_code(code_id: int, request: Request, session: AsyncSession = Depends(get_async_session)):
    require_auth(request)
    # First delete related licenses
    await session.execute(delete(License).where(License.code_id == code_id))
    # Then delete the activation code
    await session.execute(delete(ActivationCode).where(ActivationCode.id == code_id))
    await session.commit()
    return RedirectResponse("/admin/dashboard", status_code=status.HTTP_303_SEE_OTHER)


@router.post("/codes/batch-delete")
async def batch_delete_codes(
    request: Request, 
    code_ids: List[int] = Body(...),
    session: AsyncSession = Depends(get_async_session)
):
    require_auth(request)
    # First delete all related licenses
    await session.execute(delete(License).where(License.code_id.in_(code_ids)))
    # Then delete the activation codes
    await session.execute(delete(ActivationCode).where(ActivationCode.id.in_(code_ids)))
    await session.commit()
    return {"success": True, "deleted_count": len(code_ids)}


@router.get("/codes/export")
async def export_codes(request: Request, unused: bool = False, session: AsyncSession = Depends(get_async_session)):
    require_auth(request)
    stmt = select(ActivationCode)
    if unused:
        stmt = stmt.where(~ActivationCode.licenses.any())
    rows = (await session.execute(stmt)).scalars().all()
    output = io.StringIO()
    writer = csv.writer(output)
    writer.writerow(["raw_code", "quota", "used", "enabled", "duration_days", "comment"])
    for ac in rows:
        used = await session.scalar(select(func.count(License.id)).where(License.code_id == ac.id)) or 0
        writer.writerow([getattr(ac, "raw_code", ""), ac.quota, used, ac.enabled, ac.duration_days, ac.comment])
    output.seek(0)
    return StreamingResponse(output, media_type="text/csv", headers={"Content-Disposition": "attachment; filename=codes.csv"})
